import datetime
import os
import time
from selenium.common import TimeoutException
from selenium.webdriver import ActionChains, Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from tool.get_log import GetLogging

logger = GetLogging().get_logging()


class Base:
    filename = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 初始化驱动
    def __init__(self, driver):
        self.driver = driver

    # 查找元素的方法
    def base_find_element(self, loc, timeout=10, poll_frequency=0.5):
        try:
            element = WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
                EC.visibility_of_element_located(loc)
            )
            logger.info(f"已找到元素：{loc}")
            return element
        except TimeoutException as e:
            logger.error(f"未找到元素：{loc}，错误信息：{str(e)}", exc_info=True)
            raise

    # 点击元素的方法
    def base_click_element(self, loc):
        try:
            self.base_find_element(loc).click()
            logger.info(f"元素点击成功：{loc}")
        except Exception as e:
            logger.error(f"元素点击失败：{loc}，错误信息：{str(e)}", exc_info=True)
            raise

    # 在元素中输入的方法
    def base_in_element_input(self, loc, value):
        try:
            self.base_find_element(loc).send_keys(value)
            logger.info(f"向元素 {loc} 输入成功，输入内容为{value}")
        except Exception as e:
            logger.error(f"向元素 {loc} 输入失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 获取元素文本的方法
    def base_get_element_text(self, loc):
        try:
            element_text = self.base_find_element(loc).text
            logger.info(f"获取元素{loc}成功")
            return element_text
        except Exception as e:
            logger.error(f"获取元素{loc}失败，错误信息：{str(e)}", exc_info=True)
            raise

    # 获取截图的方法
    def base_get_img(self):
        try:
            now = datetime.datetime.now()
            date_folder = now.strftime("%Y%m%d")
            time_file = now.strftime("%Y%m%d_%H%M%S")
            img_dir = os.path.join(self.filename, "img", date_folder)
            os.makedirs(img_dir, exist_ok=True)
            img_path = os.path.join(img_dir, f"{time_file}.png")
            self.driver.get_screenshot_as_file(img_path)
            logger.info(f"页面截图成功，照片存放位置为{img_path}")
        except Exception as e:
            logger.error(f"页面截图失败，错误信息{str(e)}", exc_info=True)
            raise

    # 切换iframe的方法
    def base_switch_to_iframe(self, loc):
        try:
            element = self.base_find_element(loc)
            self.driver.switch_to.frame(element)
            logger.info(f"切换到iframe {loc} 成功")
        except Exception as e:
            logger.error(f"切换到iframe {loc} 失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 返回上一个frame（父级frame）
    def base_switch_to_parent_frame(self):
        try:
            self.driver.switch_to.parent_frame()
            logger.info("成功返回上一个frame")
        except Exception as e:
            logger.error(f"返回上一个frame失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 切换到默认内容（最顶层frame）
    def base_switch_to_default_content(self):
        try:
            self.driver.switch_to.default_content()
            logger.info("成功切换到默认内容（最顶层frame）")
        except Exception as e:
            logger.error(f"切换到默认内容失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 切换窗口的方法
    def base_switch_to_window(self, expect_title):
        try:
            handles = self.driver.window_handles
            titles = []
            for handle in handles:
                self.driver.switch_to.window(handle)
                current_title = self.driver.title
                titles.append(current_title)
                if expect_title in current_title:
                    logger.info(f"成功切换到标题包含 '{expect_title}' 的窗口，句柄: {handle}")
                    return
            logger.error(f"未找到含有{expect_title}的标题，所有标题：{titles}")
            raise Exception(logger.error(f"未找到含有{expect_title}的标题，所有标题：{titles}"))
        except Exception as e:
            logger.error(f"窗口切换失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 执行JavaScript
    def base_execute_script(self, js, target_loc):
        js_log = js if len(js) <= 50 else f"{js[:50]}..."
        try:
            target_element = self.base_find_element(target_loc)
            result = self.driver.execute_script(js, target_element)
            logger.info(f"JavaScript脚本执行成功（脚本: {js_log}），返回结果: {result}")
            return result
        except Exception as e:
            logger.error(f"JavaScript脚本执行失败（脚本: {js_log}），错误信息: {str(e)}", exc_info=True)
            raise

    # 页面滚动到元素位置的方法
    def base_scroll_to_element(self, loc):
        try:
            self.base_execute_script("arguments[0].scrollIntoView();", loc)
            time.sleep(0.5)
            logger.info(f"页面已滚动到元素 {loc} 的位置")
        except Exception as e:
            logger.error(f"滚动到元素 {loc} 失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 等待元素可点击的方法
    def base_wait_element_clickable(self, loc, timeout=10):
        try:
            element = WebDriverWait(self.driver, timeout).until(
                EC.element_to_be_clickable(loc)
            )
            logger.info(f"元素 {loc} 已可点击")
            return element
        except TimeoutException as e:
            logger.error(f"元素 {loc} 在 {timeout}s 内未可点击，错误信息: {str(e)}", exc_info=True)
            raise

    # 处理alert弹窗的方法
    def base_handle_alert(self, accept=True):
        action = "接受" if accept else "取消"
        try:
            alert = WebDriverWait(self.driver, 10).until(EC.alert_is_present())
            text = alert.text
            if accept:
                alert.accept()
            else:
                alert.dismiss()
            logger.info(f"{action}alert弹窗成功，弹窗内容: {text}")
            return text
        except TimeoutException:
            logger.error(f"未找到alert弹窗，无法{action}", exc_info=True)
            raise

    # 鼠标悬停的方法
    def base_move_to_element(self, loc):
        try:
            element = self.base_find_element(loc)
            ActionChains(self.driver).move_to_element(element).perform()
            time.sleep(1)
            logger.info(f"鼠标已成功悬停到元素 {loc} 上")
        except Exception as e:
            logger.error(f"鼠标悬停到元素 {loc} 失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 使用键盘快捷键的方法
    def base_keyboard_action(self, loc, key):
        # 转换按键为可读名称
        key_name = getattr(key, "__name__", str(key)) if isinstance(key, Keys) else str(key)
        try:
            element = self.base_find_element(loc)
            element.send_keys(key)
            logger.info(f"对元素 {loc} 执行键盘操作 {key_name} 成功")
        except Exception as e:
            logger.error(f"对元素 {loc} 执行键盘操作 {key_name} 失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 使用键盘组合键的方法
    def base_keyboard_combination(self, loc, modifier_key, action_key):
        modifier_name = getattr(modifier_key, "__name__", str(modifier_key))
        action_name = getattr(action_key, "__name__", str(action_key))
        try:
            element = self.base_find_element(loc)
            ActionChains(self.driver).key_down(modifier_key, element).send_keys(action_key).key_up(
                modifier_key).perform()
            time.sleep(0.5)
            logger.info(f"对元素 {loc} 执行组合键 {modifier_name} + {action_name} 成功")
        except Exception as e:
            logger.error(f"对元素 {loc} 执行组合键 {modifier_name} + {action_name} 失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 清空输入框的方法
    def base_clear_input(self, loc):
        try:
            self.base_find_element(loc).clear()
            logger.info(f"元素 {loc} 的内容已清空")
        except Exception as e:
            logger.error(f"清空元素 {loc} 的内容失败，错误信息: {str(e)}", exc_info=True)
            raise

    # 获取指定元素的截图
    def base_get_element_img(self, loc):
        try:
            element_img = self.base_find_element(loc, 20).screenshot_as_png
            logger.info(f"已经为元素{loc}截图")
            return element_img
        except Exception as e:
            logger.error(f"元素{loc}截图失败，错误信息：{e}", exc_info=True)

    # 刷新页面
    def base_refresh(self):
        try:
            self.driver.refresh()
            logger.info(f"已经刷新页面")
        except Exception as e:
            logger.error(f"刷新页面失败，错误信息：{e}", exc_info=True)

    # 处理隐藏文件
    def base_upload_hidden_file(self, loc, file_path):
        try:
            # 等待元素存在
            file_input = WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located(loc)
            )
            file_input.send_keys(file_path)
            logger.info(f"向隐藏文件上传元素 {loc} 成功上传文件：{file_path}")
        except Exception as e:
            logger.error(f"上传文件到隐藏元素 {loc} 失败，错误信息：{str(e)}", exc_info=True)
            raise
